Picture in Pictuer View Modifiers PRO
Scripting provides a set of Picture in Picture (PiP) view modifiers that allow developers to render any SwiftUI view inside a system PiP window.
These APIs abstract away the underlying AVPictureInPicture implementation and provide a declarative, script-friendly way to control PiP presentation, interaction, and lifecycle.
PiP is suitable for the following scenarios:
- Real-time status display (timers, workouts, progress indicators)
- Audio or video playback companion UI
- Lightweight views that should remain visible when the app enters background
1. PiPProps API Definition
2. Core Properties
2.1 pip.isPresented
- The single source of truth for PiP presentation
true: PiP window is presentedfalse: PiP window is dismissed
This value is typically controlled by user actions or app lifecycle events.
2.2 pip.content
- The view rendered inside the PiP window
- Strongly recommended to be a dedicated PiP view
- Should be minimal, stable, and predictable in layout
2.3 pip.maximumUpdatesPerSecond
- Default value: 30
- Limits how often the PiP view can be re-rendered per second
- One of the most important performance-related parameters
Recommended values
-
No animation / low-frequency updates Use
1–5 -
Animated PiP views Can be set to
60
Important:
Setting this value to 60 has a significant performance impact, increasing both CPU and GPU usage. This should only be used when animation is strictly required.
3. PiP Lifecycle Callbacks
(Only valid inside the PiP view)
3.1 onPipStart
-
Called when the PiP window is successfully presented
-
Typical use cases:
- Start timers
- Begin state updates
- Subscribe to data streams
3.2 onPipStop
-
Called when PiP is dismissed or stopped by the system
-
All side effects should be cleaned up here:
- Timers
- Subscriptions
- Long-running tasks
4. PiP Interaction Callbacks
(Only valid inside the PiP view)
4.1 Play / Pause Toggle
- Triggered when the user taps the play/pause control in the PiP window
isPlayingindicates the resulting playback state- Commonly used for audio, video, or workout scenarios
4.2 Skip Forward / Backward
true: skip forwardfalse: skip backward
5. Render Size Changes
onPipRenderSizeChanged
- Called whenever the PiP render size changes
- Can be used to adapt layout for different PiP sizes or orientations
6. Foreground and Background Behavior
(Only valid inside the PiP view)
6.1 pipHideOnForeground
-
When the app enters foreground:
- Determines whether an active PiP session should be stopped
-
Default:
false
6.2 pipShowOnBackground
- Automatically starts PiP when the app moves to background
- Commonly used for audio playback or real-time status displays
7. Complete Code Example
7.1 PiP Content View
7.2 Enabling PiP on a Page
8. Critical Notes
8.1 PiP views are constructed even when not presented
When isPresented is false:
- The PiP view is not visible
- But it is still constructed and participates in state binding
Therefore:
- Do not perform heavy computation in the view body
- Delay all side effects until
onPipStart - Always clean up in
onPipStop
8.2 PiP-specific modifiers must be used only in the PiP view
The following properties and callbacks:
onPipStartonPipStoponPipPlayPauseToggleonPipSkiponPipRenderSizeChangedpipHideOnForegroundpipShowOnBackground
Must be declared on the PiP content view (PipView).
Declaring them on a normal page view will result in:
- No callbacks being triggered
- Missing or incorrect state updates
- Undefined behavior
8.3 PiP is not suitable for complex UI
Avoid using the following inside PiP:
ListorScrollView- Complex or chained animations
- High-frequency state updates
- Network-driven UI rendering
PiP is designed for:
Lightweight, stable, and continuously visible system-level companion views.
9. Recommended Best Practices
- Design a dedicated, minimal PiP view
- Keep layout fixed and predictable
- Tune
maximumUpdatesPerSecondcarefully - Start all logic in
onPipStart - Always release resources in
onPipStop - Never reuse complex page-level views inside PiP
